home *** CD-ROM | disk | FTP | other *** search
/ Amiga Tools 5 / Amiga Tools 5.iso / tools / net-tools / amitrack / source / amitrackshared.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-07-16  |  13.6 KB  |  501 lines

  1. /* AmiTrackShared.c -- Shared functions between client and server */
  2.  
  3. #define __DICE_C
  4.  
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <string.h>
  8. #include <time.h>
  9.  
  10. #include <exec/types.h>
  11. #include <exec/io.h>
  12. #include <exec/lists.h>
  13. #include <exec/memory.h>
  14.  
  15. #include <clib/exec_protos.h>
  16. #include <clib/alib_protos.h>
  17. #include <clib/dos_protos.h>
  18. #include <clib/intuition_protos.h>
  19.  
  20. #include <errno.h>
  21. #include <inetd.h>
  22. #include <sys/types.h>
  23.  
  24. #include <proto/socket.h>
  25. #include <proto/exec.h>
  26. #include <sys/errno.h>
  27. #include <sys/types.h>
  28. #include <sys/socket.h>
  29. #include <sys/ioctl.h>
  30. #include <sys/syslog.h>
  31. #include <netdb.h>
  32.  
  33. #include <intuition/intuition.h>
  34.  
  35. #include <pragmas/socket_pragmas.h>
  36. #include <devices/timer.h>
  37.  
  38.  
  39. #include "AmiTrackShared.h"
  40.  
  41. struct Library * TimerBase = NULL;
  42.  
  43. void TrackExit(char * szMessage, int nCode)
  44. {
  45.     if (nCode > 0) printf("Exiting, code %i: [%s]\n",nCode, szMessage);
  46.     exit(nCode);
  47. }
  48.  
  49.  
  50. /* Wait for incoming packets or other relevant events */
  51. /* Returns a chord of event codes.  May exit if a CTRL-C is detected. */
  52. ULONG TrackWait(struct SocketStuff * sTCP, struct SocketStuff * sUDP, struct TimerStuff * Timer, struct WindowStuff * Window, struct MsgPort * msgport)
  53. {
  54.     struct fd_set fsReadSet;
  55.     int nMaxPort = -1;
  56.     ULONG ulCode = 0, ulMask = (Window  ? (1L<<Window->win->UserPort->mp_SigBit) : 0L) | 
  57.                    (Timer   ? (1L<<Timer->TimerMP->mp_SigBit) : 0L) | 
  58.                    (msgport ? (1L<<msgport->mp_SigBit) : 0L) |
  59.                    SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_D;
  60.         
  61.     FD_ZERO(&fsReadSet);
  62.     if (sUDP) {FD_SET(sUDP->fd, &fsReadSet); nMaxPort = sUDP->fd;}
  63.     if (sTCP) {FD_SET(sTCP->fd, &fsReadSet); nMaxPort = (sTCP->fd > nMaxPort) ? sTCP->fd : nMaxPort;}
  64.     
  65.     /* Wait for Data to come in */
  66.     /*         socket#     read        write   oob  timeout    other */
  67.     WaitSelect(nMaxPort+1, &fsReadSet,  NULL, NULL,    NULL, &ulMask);
  68.     
  69.     if (ulMask & SIGBREAKF_CTRL_C) return(0L);
  70.     if ((sUDP)&&(FD_ISSET(sUDP->fd, &fsReadSet))) ulCode |= CODE_UDP_SOCKET;
  71.     if ((sTCP)&&(FD_ISSET(sTCP->fd, &fsReadSet))) ulCode |= CODE_TCP_SOCKET;
  72.     if ((Timer)&&(ulMask & (1L<<Timer->TimerMP->mp_SigBit)))    ulCode |= CODE_TIMER_EXPIRED; 
  73.     if (ulMask & SIGBREAKF_CTRL_D)                            ulCode |= CODE_REFRESH;    
  74.     if ((Window)&&(ulMask & (1L<<Window->win->UserPort->mp_SigBit))) ulCode |= CODE_WINDOW_EVENT;
  75.     if ((msgport)&&(ulMask & (1L<<msgport->mp_SigBit))) ulCode |= CODE_MSGPORT;
  76.     return(ulCode);
  77. }
  78.  
  79.  
  80.  
  81. /* If clientList is NULL, sets up and returns a ClientList.
  82.    If clientList is non-NULL, frees the ClientList and returns NULL. */
  83. struct ClientList * SetupClientList(struct ClientList * ClientList)
  84. {    
  85.     if (ClientList)
  86.     {
  87.         struct Client * current;        
  88.         while(current = (struct Client *)RemHead(&ClientList->list)) FreeClient(current);
  89.         FreeMem(ClientList, sizeof(struct ClientList));
  90.         return(NULL);
  91.     }
  92.     else
  93.     {
  94.         UNLESS(ClientList = AllocMem(sizeof(struct ClientList),MEMF_CLEAR)) return(NULL);
  95.         NewList(&ClientList->list);
  96.         return(ClientList);
  97.     }
  98. }
  99.  
  100.  
  101.  
  102.  
  103.  
  104.  
  105. /* if ts is NULL, allocates and returns all the TimerStuff you need (or NULL on failure) */
  106. /* If ts is non-NULL, frees everything in ts, and returns NULL. */
  107. struct TimerStuff * SetupTimer(struct TimerStuff * ts)
  108. {
  109.     #ifdef __DICE_C
  110.     /* DICE seems to have a bug in it that makes it require this...
  111.        otherwise tv_secs and tv_micro aren't recognized!  :( */
  112.     struct timeval {
  113.         ULONG tv_secs;
  114.         ULONG tv_micro;
  115.     };
  116.     #endif
  117.         
  118.     if (ts)
  119.     {
  120.         /* Deallocate everything! */
  121.         if (ts->TimerIO)
  122.         {
  123.             if (ts->BDevOpen) 
  124.             {
  125.                 if (!(CheckIO((struct IORequest *)ts->TimerIO)))
  126.                     {
  127.                         AbortIO((struct IORequest *)ts->TimerIO);   /* Ask device to abort any pending requests */
  128.                     WaitIO((struct IORequest *)ts->TimerIO);    /* proceed when ready */
  129.                 }
  130.                     CloseDevice((struct IORequest *) ts->TimerIO);
  131.                 }
  132.                 DeleteExtIO((struct IORequest *) ts->TimerIO);
  133.             }
  134.             if (ts->TimerMP) DeletePort(ts->TimerMP);
  135.             FreeMem(ts, sizeof(struct TimerStuff));
  136.             return(NULL);
  137.     }
  138.     else
  139.     {
  140.         /* Set up the timer.device */
  141.         UNLESS(ts = AllocMem(sizeof(struct TimerStuff), MEMF_CLEAR)) return(NULL);
  142.         UNLESS((ts->TimerMP   = CreatePort(0,0))
  143.                 && (ts->TimerIO   = (struct timerequest *) CreateExtIO(ts->TimerMP, (sizeof (struct timerequest))))
  144.                 && (ts->BDevOpen  = (0 == OpenDevice(TIMERNAME,UNIT_VBLANK,(struct IORequest *)ts->TimerIO,0))))
  145.                     return(SetupTimer(ts));
  146.         
  147.         TimerBase = (struct Library *) ts->TimerIO->tr_node.io_Device;
  148.         ts->TimerIO->tr_node.io_Message.mn_ReplyPort = ts->TimerMP;
  149.         ts->TimerIO->tr_node.io_Command  = TR_ADDREQUEST;
  150.         ts->TimerIO->tr_node.io_Flags      = 0;
  151.         ts->TimerIO->tr_node.io_Error      = 0;
  152.         ts->TimerIO->tr_time.tv_secs       = 0;
  153.         ts->TimerIO->tr_time.tv_micro      = 0;     
  154.         return(ts);
  155.     }
  156. }
  157.  
  158.  
  159.  
  160. /* Removes the client entry with the hostname szHostName from the ClientList.  */
  161. /* Returns TRUE if an item was removed, else FALSE. */
  162. BOOL RemoveClient(struct ClientList * ClientList, char * szHostName)
  163. {
  164.     struct Client * client = (struct Client *) ClientList->list.lh_Head;
  165.     
  166.     while(client->node.ln_Succ)
  167.     {        
  168.         UNLESS(strcmp(szHostName, client->hostname))
  169.         {
  170.             /* found our victim! */
  171.             Remove((struct Node *)client); FreeClient(client); ClientList->nListLength--;
  172.             return(TRUE);
  173.         }
  174.         client = client->node.ln_Succ;
  175.     }
  176.     return(FALSE);
  177. }
  178.  
  179.  
  180.  
  181. /* Frees the given client structure.  Safe to use even if
  182.    not all fields were allocated */
  183. void FreeClient(struct Client * client)
  184. {        
  185.     UNLESS(client) return;
  186.     if (client->hostname) FreeMem(client->hostname, strlen(client->hostname)+1);
  187.     if (client->comment)  FreeMem(client->comment,  strlen(client->comment)+1);
  188.     FreeMem(client, sizeof(struct Client));
  189. }        
  190.  
  191.  
  192.  
  193.  
  194.  
  195. /* Set/Reset timer.device to signal us in nSecs seconds + nMicros microseconds */
  196. void SetTimer(struct TimerStuff * ts, int nSecs, int nMicros)
  197. {
  198.      /* First make sure there is no previous timer pending */
  199.         if (!(CheckIO((struct IORequest *) ts->TimerIO)))
  200.         {
  201.             AbortIO((struct IORequest *) ts->TimerIO);
  202.             WaitIO((struct IORequest *) ts->TimerIO);
  203.         }
  204.                
  205.         ts->TimerIO->tr_time.tv_secs  = nSecs;                                        
  206.         ts->TimerIO->tr_time.tv_micro = nMicros;
  207.         
  208.         /* Start ze timer */
  209.         SendIO((struct IORequest *)ts->TimerIO);
  210. }
  211.  
  212.  
  213.  
  214. /* Find the client structure with the given hostname in the client list.
  215.    Failing that, create one and insert it into the list.  Failing
  216.    that, return NULL.  If szOptComment is non-NULL, it will be created/
  217.    replaced in the returned Client. */
  218. struct Client * GetClient(struct ClientList * ClientList, ULONG ulIPAddress, char * szHostName, char * szOptComment)
  219. {
  220.     struct Client * client = (struct Client *) ClientList->list.lh_Head;
  221.     struct Client * prevClient = NULL;
  222.     int nCompare;
  223.  
  224.     UNLESS(ulIPAddress) return(NULL);
  225.     
  226.     while (client->node.ln_Succ)
  227.     {
  228.         nCompare = strcmp(szHostName, client->hostname);
  229.         if ((nCompare == 0)&&(ulIPAddress == client->ulIPAddress))
  230.         {
  231.             if (szOptComment) ReplaceAllocedString(&client->comment, szOptComment);
  232.             return(client);
  233.         }
  234.         if (nCompare < 0) break;    /* Not in the list--insert it here */
  235.         prevClient = client;
  236.         client = (struct Client *)client->node.ln_Succ;
  237.     }
  238.  
  239.     /* If we got here, we need to add the client to the list */
  240.     UNLESS(client = NewClient(ulIPAddress, szHostName, szOptComment)) return(NULL);
  241.     Insert((struct List *)ClientList, (struct Node *)client, (struct Node *)prevClient);  ClientList->nListLength++;
  242.     return(client);
  243. }
  244.  
  245.  
  246.  
  247. /* Allocate a new Client structure and initialize its fields correctly,
  248.    or return NULL on failure. */
  249. struct Client * NewClient(ULONG ulIPAddress, char * szHostName, char * szOptComment)
  250. {
  251.     struct Client * client = NULL;
  252.     
  253.     UNLESS(szOptComment) szOptComment = "";
  254.     UNLESS((client                = AllocMem(sizeof(struct Client),  MEMF_CLEAR))
  255.         && (client->hostname       = AllocMem(strlen(szHostName)+1,   MEMF_ANY))
  256.         && (strcpy(client->hostname, szHostName))
  257.         && (client->comment        = AllocMem(strlen(szOptComment)+1, MEMF_ANY))
  258.         && (strcpy(client->comment,  szOptComment)))
  259.     {    
  260.         FreeClient(client);    /* cleanup any partial allocations */
  261.         return(NULL);
  262.     }
  263.     client->ulIPAddress = ulIPAddress;
  264.     client->tDateStamp  = time(NULL);
  265.     return(client);
  266. }
  267.  
  268.  
  269.  
  270.  
  271.  
  272. /* Deallocate the old string, allocate the new string! */
  273. /* Give it a pointer to the pointer to the old string, and a pointer to the new string */
  274. /* Can also server to just deallocate the old, if the new string is NULL */
  275. void ReplaceAllocedString(char ** szOldString, char * szNewString)
  276. {
  277.     char * pcTemp = NULL;
  278.  
  279.     UNLESS(szOldString) return;
  280.     if (szNewString)
  281.     {
  282.         UNLESS(pcTemp = AllocMem(strlen(szNewString)+1, MEMF_ANY)) return;
  283.         strcpy(pcTemp, szNewString);
  284.     }
  285.     if (*szOldString) FreeMem(*szOldString, strlen(*szOldString)+1);
  286.     *szOldString = pcTemp;
  287.     return;
  288. }
  289.  
  290.  
  291.  
  292. /* If ss is NULL, allocates and returns a new SocketStuff structure.
  293.    If ss is non-NULL, deallocates it and returns NULL. */
  294. struct SocketStuff * SetupSocket(struct SocketStuff * ss, int nPort, LONG lSocketType)
  295. {
  296.     BOOL BBind = TRUE;
  297.     
  298.     /* If nPort is negative, use its absolute value and don't try to bind() it */
  299.     if (nPort < 0)
  300.     {
  301.         nPort = -nPort;
  302.         BBind = FALSE;
  303.     }
  304.     
  305.     if (ss)
  306.     {
  307.         if (ss->fd >= 0) CloseSocket(ss->fd);
  308.         FreeMem(ss, sizeof(struct SocketStuff));
  309.         return(NULL);
  310.     }
  311.     else
  312.     {
  313.         UNLESS(ss = AllocMem(sizeof(struct SocketStuff), MEMF_CLEAR)) return(NULL);
  314.         ss->lSocketType = lSocketType;
  315.  
  316.         if ((ss->fd = socket(AF_INET, ss->lSocketType, 0)) < 0) return(SetupSocket(ss,0,0));
  317.  
  318.             bzero(&ss->saAddr, sizeof(struct sockaddr_in));
  319.         ss->saAddr.sin_family        = AF_INET;
  320.         ss->saAddr.sin_addr.s_addr = htonl(INADDR_ANY);
  321.           ss->saAddr.sin_port        = htons(nPort);
  322.         if ((BBind)&&(bind(ss->fd, (struct sockaddr *) &ss->saAddr, sizeof(struct sockaddr_in)))) return(SetupSocket(ss,0,0));
  323.         return(ss);    
  324.     }
  325. }
  326.  
  327.  
  328.  
  329.  
  330. /* Downloads, allocates, and returns a ClientList if possible.
  331.    Returns NULL on failure. */
  332. struct ClientList * GetTrackList(char * szHostName, int nPortNum)
  333. {
  334.     struct ClientList * ClientList = NULL;
  335.     struct SocketStuff * sSocket = NULL;
  336.     struct hostent * hp;
  337.     char * pcName, * pcComment;
  338.     ULONG ulIPAddress;
  339.     
  340.     UNLESS(sSocket = SetupSocket(NULL, -nPortNum, SOCK_STREAM)) return(NULL);
  341.     UNLESS(ClientList = SetupClientList(NULL)) 
  342.     {
  343.         SetupSocket(sSocket,0,0);
  344.         return(NULL);
  345.     }
  346.     UNLESS(hp = gethostbyname(szHostName))
  347.     {
  348.         SetupSocket(sSocket,0,0);
  349.         return(NULL);
  350.     }
  351.     bzero(&sSocket->saAddr, sizeof(struct sockaddr_in));
  352.         bcopy(hp->h_addr, (char *)&sSocket->saAddr.sin_addr.s_addr, hp->h_length);
  353.         sSocket->saAddr.sin_family = hp->h_addrtype;
  354.         sSocket->saAddr.sin_port   = htons(nPortNum);
  355.  
  356.     if (connect(sSocket->fd, (struct sockaddr *) &sSocket->saAddr, sizeof(struct sockaddr_in)) < 0)
  357.     {
  358.         SetupSocket(sSocket,0,0);
  359.         SetupClientList(ClientList);
  360.         return(NULL);
  361.     }
  362.     
  363.     /* Now just read & record! */
  364.     while(FillInfos(sSocket, &pcName, &ulIPAddress, &pcComment)) GetClient(ClientList, ulIPAddress, pcName, pcComment);
  365.  
  366.     SetupSocket(sSocket, 0, 0);
  367.     return(ClientList);
  368. }
  369.  
  370.  
  371. /* Returns TRUE if *pSetName and *pSetComment are valid, else FALSE on error. */
  372. BOOL FillInfos(struct SocketStuff * sSocket, char **pSetName, ULONG * ulIPAddress, char **pSetComment)
  373. {
  374.     static char szBuf[1000];
  375.     ULONG nIndex = 0L;
  376.     int nReadULONG = 0;
  377.     char * pcIPBinary = (char *) ulIPAddress;
  378.         
  379.     *pSetName = szBuf;
  380.     *pSetComment = NULL;
  381.     *ulIPAddress = 0L;
  382.     
  383.     while(1)
  384.     {
  385.         if (recv(sSocket->fd, &szBuf[nIndex], 1, 0L) <= 0) return(FALSE);
  386.         if (nReadULONG)     /* we read the IP address as 4 binary bytes */
  387.         {
  388.             *pcIPBinary = szBuf[nIndex]; pcIPBinary++;
  389.             UNLESS(--nReadULONG) return(TRUE);
  390.         }
  391.         else if (szBuf[nIndex] == '\0')
  392.         {
  393.              if (*pSetComment) nReadULONG   = sizeof(ULONG);
  394.                          else *pSetComment = &szBuf[nIndex+1];
  395.         }
  396.         
  397.         if ((++nIndex) >= sizeof(szBuf)) return(FALSE);
  398.     }
  399. }
  400.  
  401.  
  402. void ClearTrackScreen(void)
  403. {
  404.     printf("%c",12);
  405. }
  406.  
  407. /* Server's output to stdout for the local user to see. */
  408. void PrintClientList(struct ClientList * ClientList)
  409. {
  410.     struct Client * client = (struct Client *) ClientList->list.lh_Head;
  411.     int nTemp = 0;
  412.     time_t tTime = time(NULL);
  413.     
  414.     printf(" Num | Age | Hostname                  | Comment\n");
  415.       printf("-----+-----+---------------------------+----------------------\n");
  416.     while (client->node.ln_Succ)
  417.     {
  418.         printf("#%03i | %03lu | %-25s | %s\n", 
  419.             nTemp,tTime - client->tDateStamp, 
  420.             client->hostname,client->comment);
  421.         client = client->node.ln_Succ;
  422.         nTemp++;
  423.     }
  424.     putchar('\n');
  425. }
  426.  
  427.  
  428. int MakeReq(char *sTitle, char *sText, char *sGadgets)
  429. {
  430.     struct EasyStruct myreq;
  431.     int nResult;
  432.  
  433.     UNLESS(sTitle)   sTitle   = "AmiTrack Message";
  434.     UNLESS(sText)    sText    = "Check this out!";
  435.     UNLESS(sGadgets) sGadgets = "OK";
  436.  
  437.     myreq.es_TextFormat   = sText;
  438.     myreq.es_Title        = sTitle;
  439.     myreq.es_GadgetFormat = sGadgets;
  440.  
  441.     nResult = EasyRequest(NULL, &myreq, NULL, NULL, NULL);
  442.  
  443.     return(nResult);
  444. }
  445.  
  446.  
  447. /* Returns a pointer to the first non-space character in the string */
  448. char * PastSpaces(char * pcString)
  449. {
  450.     while(1) 
  451.     {
  452.         if (*pcString == ' ') pcString++;
  453.                  else return(pcString); 
  454.     }
  455. }
  456.  
  457.  
  458. /* Chops off any trailing blanks and returns the string */
  459. char * RemoveTrailingSpaces(char * pcString)
  460. {
  461.     char * pcTemp = strchr(pcString,'\0');
  462.     
  463.     pcTemp--;
  464.     while((pcTemp > pcString)&&(*pcTemp == ' ')) pcTemp--;
  465.     pcTemp++;
  466.     
  467.     *pcTemp = '\0';
  468.     
  469.     return(pcTemp);
  470. }
  471.  
  472.  
  473. /* Replaces all unprintable characters in pcString with ' ' */
  474. /* Hopefully this will stop people from sending e.g. "talkbombs" */
  475. /* Returns pcString. */
  476. char * RemoveUnprintableChars(char * pcString)
  477. {
  478.     char * pcTemp = pcString;
  479.     
  480.     while(*pcTemp)
  481.     {
  482.         if (*pcTemp < ' ') *pcTemp = ' ';
  483.         pcTemp++;
  484.     }
  485.     return(pcString);
  486. }
  487.  
  488.  
  489. /* Makes pcString lower case */
  490. char * ToLower(char * pcString)
  491. {
  492.     char * pcTemp = pcString;
  493.     
  494.     while(*pcTemp) 
  495.     {
  496.         if ((*pcTemp >= 'A')&&(*pcTemp <= 'Z'))
  497.             *pcTemp += 'a'-'A';
  498.         pcTemp++;
  499.     }
  500.     return(pcString);
  501. }